﻿using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Domain.Services;
using Abp.Domain.Uow;
using Mt.Site.Core.Navigations.Entities;
using Mt.Site.Core.Navigations.Permissions;
using Mt.Site.Core.Navigations.Values;
using Mt.Site.Core.Storage;
using Mt.Site.Core.Synchronization.Data;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Mt.Site.Core.Synchronization.Navigations
{
    public class MenuInfoAutoSyncManager : DomainService, IMenuInfoAutoSyncManager
    {
        private readonly IRepository<ChannelObject, Guid> _channelObjectRepository;
        private readonly IRepository<MenuConfig, Guid> _menuConfigRepository;

        private readonly ISynchronizationHelper _synchronizationHelper;

        private readonly IMenuInfoStore _menuInfoStore;

        private readonly IRepository<FileObject, Guid> _fileObjectRepository;

        public MenuInfoAutoSyncManager(
            ISynchronizationHelper synchronizationHelper,
            IRepository<ChannelObject, Guid> channelObjectRepository,
            IRepository<MenuConfig, Guid> menuConfigRepository,
            IMenuInfoStore menuInfoStore,
            IRepository<FileObject, Guid> fileObjectRepository)
        {
            _synchronizationHelper = synchronizationHelper;

            _channelObjectRepository = channelObjectRepository;
            _menuConfigRepository = menuConfigRepository;
            _menuInfoStore = menuInfoStore;
            _fileObjectRepository = fileObjectRepository;
        }

        #region Config
        
        public async Task<Guid> UpdateConfigSync(CreateOrUpdateSynchorizeStore input)
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var notify = new NoticeArgs();
                try
                {
                    var syncInfoStore = CheckConfigAndAutoSync(input.TargetLanguage, input.ToTenantId, input.Id, notify);
                    notify.Type = input.OptionType;

                    if (syncInfoStore != null && syncInfoStore.ToId != Guid.Empty)
                    {
                       await _synchronizationHelper.SendNoticeForSuccessAsync(
                            notify,
                            notify.MenuId, 
                            new List<string> { MenuPermissions.Pages_Tenant_MenusInfo_Config_Edit }
                            );
                        return syncInfoStore.ToId;
                    }
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForFailAsync(
                            notify,
                            notify.MenuId,
                            new List<string> { MenuPermissions.Pages_Tenant_MenusInfo_Config_Edit }
                            );
                    }
                    throw;
                }
                return Guid.Empty;
            }
        }

        private AutoSyncInfoStore CheckConfigAndAutoSync(string targetLanguage, int toTenantId, Guid fromId, NoticeArgs args)
        {
            var syncInfoStore = new AutoSyncInfoStore();
            var fromEntity = _menuConfigRepository.FirstOrDefault(fromId);
            if (fromEntity != null)
            {
                args.FromId = fromEntity.Id;
                args.MenuId = fromEntity.MenuId;
                args.Title = "Config";
                args.ToLanguage = targetLanguage;
                args.ToTenantId = toTenantId;

                var toEntity = _menuConfigRepository.FirstOrDefault(
                        item =>  item.TenantId == toTenantId && item.MenuId == fromEntity.MenuId && item.Type == fromEntity.Type);

                if (toEntity != null)
                {
                    syncInfoStore.IsAutoSync = _synchronizationHelper.ShouldSynchronize(toEntity);
                    if (syncInfoStore.IsAutoSync)
                    {
                        syncInfoStore.ToId = _menuInfoStore.UpdateConfigSync(toEntity, fromEntity);
                    }
                }

                if (syncInfoStore.ToId != Guid.Empty)
                {
                    args.ToId = syncInfoStore.ToId;
                    return syncInfoStore;
                }
            }

            return null;
        }

        #endregion

        #region ImgText

        [UnitOfWork]
        public async Task<Guid> UpdateImgTextSync(SyncArgs_Guid input)
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var notify = new NoticeArgs();
                notify.MenuId = input.MenuId;
                try
                {
                    var syncInfoStore = CheckChannelObjectAndAutoSync(input.TargetLanguage, input.ToTenantId, input.Id, notify, true);
                    notify.Type = input.OptionType;

                    if (syncInfoStore != null && syncInfoStore.ToId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForSuccessAsync(
                            notify,
                            notify.MenuId,
                            new List<string> { MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Edit }
                            );
                        return syncInfoStore.ToId;
                    }
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                       await _synchronizationHelper.SendNoticeForFailAsync(
                            notify,
                            notify.MenuId,
                            new List<string> { MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Edit }
                            );
                    }
                    throw;
                }
                return Guid.Empty;
            }
        }

        [UnitOfWork]
        public async Task<Guid> DeleteImgTextSync(SyncArgs_Guid input)
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var notify = new NoticeArgs();
                notify.MenuId = input.MenuId;
                try
                {
                    var syncInfoStore = CheckChannelObjectAndAutoSync(input.TargetLanguage, input.ToTenantId, input.Id, notify);
                    notify.Type = input.OptionType;

                    if (syncInfoStore == null || syncInfoStore.ToId == Guid.Empty)
                    {
                        return Guid.Empty;
                    }
                    if (syncInfoStore.IsFromEntityHasDeleted.HasValue && !syncInfoStore.IsFromEntityHasDeleted.Value)
                    {
                        return Guid.Empty;
                    }

                    await _channelObjectRepository.DeleteAsync(syncInfoStore.ToId);
                    await _fileObjectRepository.DeleteAsync(
                           item => item.ContentId == syncInfoStore.ToId && item.Language == input.TargetLanguage && item.TenantId == input.ToTenantId);
                    await _synchronizationHelper.SendNoticeForSuccessAsync(
                        notify,
                        notify.MenuId,
                        new List<string> { MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Delete }
                        );
                    return syncInfoStore.ToId;
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                       await  _synchronizationHelper.SendNoticeForFailAsync(
                            notify,
                            notify.MenuId,
                            new List<string> { MenuPermissions.Pages_Tenant_MenusInfo_ImageText_Delete }
                            );
                    }
                    throw;
                }
            }
        }

        
        private AutoSyncInfoStore CheckChannelObjectAndAutoSync(string targetLanguage, int toTenantId, Guid fromId, NoticeArgs args, bool isRequireSync = false)
        {
            var syncInfoStore = new AutoSyncInfoStore();
            var fromEntity = _channelObjectRepository.FirstOrDefault(fromId);
            if (fromEntity != null)
            {
                args.FromId = fromEntity.Id;
                args.Title = fromEntity.Title;
                args.ToLanguage = targetLanguage;
                args.ToTenantId = toTenantId;

                if (fromEntity is ISoftDelete)
                {
                    syncInfoStore.IsFromEntityHasDeleted = (fromEntity as ISoftDelete).IsDeleted;
                }

                var toEntity = _channelObjectRepository.FirstOrDefault(
                        item => item.SourceID == fromEntity.Id && item.Language == targetLanguage && item.TenantId == toTenantId);

                if (isRequireSync)
                {
                    if (toEntity != null)
                    {
                        syncInfoStore.IsAutoSync = _synchronizationHelper.ShouldSynchronize(toEntity);
                        if (syncInfoStore.IsAutoSync)
                        {
                            syncInfoStore.ToId = _menuInfoStore.UpdateChannelObjectSync(toEntity, fromEntity);
                        }
                    }

                    if (syncInfoStore.ToId != Guid.Empty)
                    {
                        args.ToId = syncInfoStore.ToId;
                        return syncInfoStore;
                    }
                }
                else
                {
                    if (toEntity != null)
                    {
                        syncInfoStore.IsAutoSync = _synchronizationHelper.ShouldSynchronize(toEntity);
                        if (syncInfoStore.IsAutoSync)
                        {
                            syncInfoStore.ToId = toEntity.Id;
                            args.ToId = toEntity.Id;
                            return syncInfoStore;
                        }
                    }
                }
            }

            return null;
        }

        #endregion
    }
}
